/**
 * Copyright (c) 2009  Collaborative Development Group, C.S. Dept., University of Bari
 *
 * All rights reserved. This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0  which accompanies this distribution, and is 
 * available at http://www.eclipse.org/legal/epl-v10.html
 */
package it.uniba.di.cdg.penelope.internal;

import java.util.List;
import java.util.Map;

import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;

/**
 * 
 */
public class LazyInjector implements Injector {

	private Injector delegate;
	
	private final List<Module> modules;

	/**
	 * @param modules
	 */
	public LazyInjector( List<Module> modules ) {
		super();
		this.modules = modules;
	}
	
	/**
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#createChildInjector(java.lang.Iterable)
	 */
	public Injector createChildInjector( Iterable<? extends Module> arg0 ) {
		return getOrCreateDelegate().createChildInjector( arg0 );
	}

	/**
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#createChildInjector(com.google.inject.Module[])
	 */
	public Injector createChildInjector( Module... arg0 ) {
		return getOrCreateDelegate().createChildInjector( arg0 );
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#findBindingsByType(com.google.inject.TypeLiteral)
	 */
	public <T> List<Binding<T>> findBindingsByType( TypeLiteral<T> arg0 ) {
		return getOrCreateDelegate().findBindingsByType( arg0 );
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getBinding(java.lang.Class)
	 */
	public <T> Binding<T> getBinding( Class<T> arg0 ) {
		return getOrCreateDelegate().getBinding( arg0 );
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getBinding(com.google.inject.Key)
	 */
	public <T> Binding<T> getBinding( Key<T> arg0 ) {
		return getOrCreateDelegate().getBinding( arg0 );
	}

	/**
	 * @return
	 * @see com.google.inject.Injector#getBindings()
	 */
	public Map<Key<?>, Binding<?>> getBindings() {
		return getOrCreateDelegate().getBindings();
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getInstance(java.lang.Class)
	 */
	public <T> T getInstance( Class<T> arg0 ) {
		return getOrCreateDelegate().getInstance( arg0 );
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getInstance(com.google.inject.Key)
	 */
	public <T> T getInstance( Key<T> arg0 ) {
		return getOrCreateDelegate().getInstance( arg0 );
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getMembersInjector(java.lang.Class)
	 */
	public <T> MembersInjector<T> getMembersInjector( Class<T> arg0 ) {
		return getOrCreateDelegate().getMembersInjector( arg0 );
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getMembersInjector(com.google.inject.TypeLiteral)
	 */
	public <T> MembersInjector<T> getMembersInjector( TypeLiteral<T> arg0 ) {
		return getOrCreateDelegate().getMembersInjector( arg0 );
	}

	/**
	 * @return
	 * @see com.google.inject.Injector#getParent()
	 */
	public Injector getParent() {
		return getOrCreateDelegate().getParent();
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getProvider(java.lang.Class)
	 */
	public <T> Provider<T> getProvider( Class<T> arg0 ) {
		return getOrCreateDelegate().getProvider( arg0 );
	}

	/**
	 * @param <T>
	 * @param arg0
	 * @return
	 * @see com.google.inject.Injector#getProvider(com.google.inject.Key)
	 */
	public <T> Provider<T> getProvider( Key<T> arg0 ) {
		return getOrCreateDelegate().getProvider( arg0 );
	}

	/**
	 * @param arg0
	 * @see com.google.inject.Injector#injectMembers(java.lang.Object)
	 */
	public void injectMembers( Object arg0 ) {
		getOrCreateDelegate().injectMembers( arg0 );
	}
	
	private synchronized Injector getOrCreateDelegate() {
		if (delegate == null) {
			delegate = Guice.createInjector( modules );
		}
		return delegate;
	}
}
